import { message } from 'antd';
import moment from 'moment';
import SparkMD5 from 'spark-md5';
import { getMessage } from '@inbiz/react';
import { IChildFolderConfig } from '../interface';
import { GetFolderById } from '../services';
import { getFolderName, getQueryString } from '@inbiz/utils';

export interface IParams {
  file: { [key: string]: any };
  accept?: { type: string }[];
  fileMode?: string;
  fileSize?: string;
}

// 大小转换集合
const sizeEnum = {
  B: 1,
  KB: 1024,
  M: 1024 * 1024
}

/**
 * 获取组件属性
 * @param componentName 组件名
 * @param allProps props集合
 * @returns 返回对应组件的props
 */
const getComponentProps = (componentName: string, allProps: any) => {
  const componentProps = {};

  Object.keys(allProps).forEach((propName) => {
    if (propName.indexOf(componentName + '-') === 0) {
      const componentPropName = propName.substr(componentName.length + 1);
      componentProps[componentPropName] = allProps[propName];
    }
  });

  return componentProps;
};

/**
 * 判断文件状态是否为退出或者删除
 * @param statusToCheck 文件状态
 * @param statusEnum 状态集合
 * @returns 返回当前状态是否为退出或者删除
 */
const isFileGone = (statusToCheck: string, statusEnum: { CANCELED: string; DELETED: string }) => {
  return [statusEnum.CANCELED, statusEnum.DELETED].indexOf(statusToCheck) >= 0;
};

/**
 * 查找某个文件是否存在于文件集合里
 * @param files 文件集合
 * @param id 文件的标识
 * @returns 返回文件的索引
 */
const findFileIndex = (files: { [key: string]: any }[], id: string | number) => {
  let visibleFileIndex = -1;

  files.some((file, index) => {
    if (file.id === id) {
      visibleFileIndex = index;
      return true;
    }
  });

  return visibleFileIndex;
};

/**
 * 文件大小单位转换
 * @param size 文件的大小
 * @returns 返回转换后文件的大小
 */
const formatSizeAndUnits = (size: number, returnType?: string) => {
  const units = {
    byte: 'B',
    kilobyte: 'KB',
    megabyte: 'MB',
    gigabyte: 'GB',
    terabyte: 'TB',
  };
  let formattedSize, formattedUnits;

  if (size < 1e3) {
    formattedSize = size;
    formattedUnits = units.byte;
  } else if (size >= 1e3 && size < 1e6) {
    formattedSize = (size / 1e3).toFixed(2);
    formattedUnits = units.kilobyte;
  } else if (size >= 1e6 && size < 1e9) {
    formattedSize = (size / 1e6).toFixed(2);
    formattedUnits = units.megabyte;
  } else if (size >= 1e9 && size < 1e12) {
    formattedSize = (size / 1e9).toFixed(2);
    formattedUnits = units.gigabyte;
  } else {
    formattedSize = (size / 1e12).toFixed(2);
    formattedUnits = units.terabyte;
  }

  return returnType === 'object'
    ? { formattedSize, formattedUnits }
    : `${formattedSize}${formattedUnits}`;
};

/**
 * 转换重名策略
 * @param strategy 当前策略
 * @returns 返回该策略对应的显示文字
 */
const conversionStrategy = (strategy: string) => {
  switch (strategy) {
    case 'majorUpgrade':
      return getMessage('inbizUpload.majored');
    case 'minorUpgrade':
      return getMessage('inbizUpload.minored');
    case 'publishMajorVersion':
      return getMessage('inbizUpload.publishMajorVersioned');
    case 'overlayLatestVersion':
      return getMessage('inbizUpload.overlayLatestVersioned');
    case 'rename':
      return getMessage('inbizUpload.renamed');
    case 'skip':
      return getMessage('inbizUpload.skiped');
    default:
      return getMessage('inbizUpload.uploadSuccess');
  }
};

/**
 * 拆分文件名
 * @param name 文件名
 * @returns 返回名称和扩展名
 */
const splitFileName = (name: string = '') => {
  return {
    name: name.indexOf('.') != -1 ? name.substring(0, name.lastIndexOf('.')) : name.substring(0),
    ext: name.substring(name.lastIndexOf('.') + 1),
  };
};

/**
 * 验证文件类型和大小
 * @param params 文件的相关信息
 * @returns 返回是否验证通过
 */
const fileValidate = (params: IParams) => {
  // 判断文件类型
  let isThrough: boolean = true;
  const { file, accept = [], fileMode, fileSize = '' } = params;
  const { ext } = splitFileName(file.name);
  if (accept.length > 0) {
    if (fileMode === 'allow') {
      isThrough = accept.some((itme) => itme.type === ext);
    } else {
      isThrough = !accept.some((itme) => itme.type === ext);
    }
  }
  if (!isThrough) {
    message.destroy();
    message.error(
      `${fileMode === 'allow' ? getMessage('inbizUpload.allow') : getMessage('inbizUpload.ban')
      }${getMessage('inbizUpload.upload')}${accept.map((item) => item.type).join('、')}${getMessage(
        'inbizUpload.fileType',
      )}`,
    );
    return isThrough;
  }
  // 判断文件大小
  if (fileSize !== '') {
    const size = file.size;
    const value = fileSize.replace(/[^\d]/g, '');
    const unit = fileSize.replace(/[\d]/g, '');
    if (unit === 'KB' && size / 1024 > Number(value)) {
      isThrough = false;
    }
    if (unit === 'MB' && size / 1024 / 1024 > Number(value)) {
      isThrough = false;
    }
    if (unit === 'GB' && size / 1024 / 1024 / 1024 > Number(value)) {
      isThrough = false;
    }
  }
  if (!isThrough) {
    message.destroy();
    message.error(`${getMessage('inbizUpload.maxFileSize')}${fileSize}`);
    return isThrough;
  }
  return isThrough;
};

/**
 * 子文件夹配置项数据转换
 * @param path 文件路径
 * @param data 子文件夹配置集合
 * @param appInfo 当前app应用信息
 * @returns 返回组装后文件路径
 */
const pathConvert = (path: string = '', data: any, appInfo: any) => {
  data.forEach((item: any) => {
    switch (item.model) {
      case 'fixedChar':
        path += item.values;
        break;
      case 'date':
        path += moment().format(item.values);
        break;
      case 'createrName':
        path += appInfo?.userInfoByToken?.Name;
        break;
      case 'createrDepNumber':
        path += appInfo?.userInfoByToken?.MainDepartmentCode;
        break;
      case 'createrDepName':
        path += appInfo?.userInfoByToken?.MainDepartmentName;
        break;
    }
  });
  return path;
};

/**
 * 验证子文件夹名称长度
 * @param value 文件夹名称
 * @returns 返回是否验证通过
 */
const lengthVerify = (value: string) => {
  const pathArr = value.split('/');
  return pathArr.some((item) => item.length > 240);
};

/**
 * 验证子文件夹命名规范
 * @param config 子文件夹配置
 * @param appInfo 当前app应用信息
 * @returns 返回是否通过验证
 */
const childFolderValidate = (config?: string | IChildFolderConfig) => {
  if (!config) return;
  if (typeof config === 'string') {
    const pathArr = config.split('/') || [];
    if (pathArr?.[1]) {
      if (lengthVerify(pathArr[1])) {
        message.error(getMessage('inbizUpload.folderName1Error'));
        return;
      }
    }
    if (pathArr?.[2]) {
      if (lengthVerify(pathArr[2])) {
        message.error(getMessage('inbizUpload.folderName2Error'));
        return;
      }
    }
    return config;
  }
  // 文件上传，图片上传，附件列表的子文件夹配置处理
  const { level1FolderPath = '', level2FolderPath = '' } = config;
  if (lengthVerify(level1FolderPath)) {
    message.error(getMessage('inbizUpload.folderName1Error'));
    return;
  }
  if (lengthVerify(level2FolderPath)) {
    message.error(getMessage('inbizUpload.folderName2Error'));
    return;
  }
  return `${level1FolderPath}${level2FolderPath}`;
};

/**
 * 更新文件验证
 */
const updateFileValidate = (fileName: string, file: { [key: string]: any }) => {
  const { ext: oldExt } = splitFileName(fileName);
  const { ext: newExt } = splitFileName(file.name);
  if (oldExt !== newExt) {
    message.destroy();
    message.error(getMessage('inbizUpload.updateFileError'));
    return false;
  }
  return true;
};

/**
 * 判断文件是否已上传完成
 * @param uploadStatus 文件状态
 * @returns 返回对应的icon名称
 */
const getFilesStatus = (uploadStatus: string) => {
  if (uploadStatus === 'loading') {
    return 'icon-a-zhengzaishangchuan-xuanzhuanxiaoguoshangchuandanceng';
  } else {
    return 'icon-yiwancheng';
  }
};

/**
 *
 * @param visibleFiles 文件列表
 * @param status 状态
 * @returns 返回满足条件的数据个数
 */
const getFileFailedNum = (visibleFiles: { [key: string]: any }[], status: string) => {
  const newList = visibleFiles.filter(
    (item) => item.status === status && item?.file?.strategy !== 'skip',
  );
  return newList.length;
};

const isUploadComplete = (status: string, statusEnum: any) => {
  return (
    status === statusEnum.UPLOAD_FAILED ||
    status === statusEnum.UPLOAD_SUCCESSFUL ||
    status === statusEnum.CANCELED
  );
};

const isCancelable = (status: string, statusEnum: any) => {
  return (
    [
      statusEnum.DELETE_FAILED,
      statusEnum.PAUSED,
      statusEnum.QUEUED,
      statusEnum.UPLOAD_RETRYING,
      statusEnum.SUBMITTED,
      statusEnum.UPLOADING,
      statusEnum.UPLOAD_FAILED,
      statusEnum.UPLOAD_EXISNAME
    ].indexOf(status) >= 0
  );
};
const isDeletable = (status: string, statusEnum: any) => {
  return [statusEnum.DELETE_FAILED, statusEnum.UPLOAD_SUCCESSFUL].indexOf(status) >= 0;
};

/**
 * 获取文件夹路径
 * @param folderId 文件夹id
 * @returns 返回格式化后的路径
 */
const getPath = async (folderId: string | number) => {
  const code = getQueryString('code');
  const topFolders: any = await getFolderName();
  const data = await GetFolderById({ folderId, code });
  if (!data) return;
  let namePath = code ? data.path : data.folder?.namePath;
  const cache = namePath.split('\\');
  /**
   * PublicRoot 企业库
   * PersonalRoot 个人库
   * Team 团队库
   */
  if (cache[0] === 'PublicRoot') {
    namePath = namePath.replace('PublicRoot', topFolders?.qiyeku);
  }
  if (cache[0] === 'PersonalRoot') {
    namePath = namePath.replace('PersonalRoot', topFolders?.gerenku);
  }
  if (cache[0] === 'Team') {
    namePath = namePath.replace('Team', topFolders?.tuanduiku);
  }
  const path = namePath.split('\\').join('/');
  return path;
};

/**
 * 删除满足条件的文件元素
 * @param id 文件唯一标识id
 * @param list 文件集合
 */
const removeVisibleFile = (id: string | number, list: any) => {
  const visibleFileIndex = findFileIndex(list, id);
  if (visibleFileIndex >= 0) {
    list.splice(visibleFileIndex, 1);
  }
  return list;
};

/**
 * 文件分块
 * @param file 文件
 * @param chunkSize 分块大小
 * @param type 类型，如果为headMd5，就切割1M
 * @returns 返回分块的数组
 */
const fileChunk = (file: File, chunkSize: number, type?: 'headMd5') => {
  let chunks = [];
  if (type == 'headMd5') {
    chunks.push(file.slice(0, 1024 * 1024));
    return chunks;
  }
  for (let i = 0; i < file.size; i = i + chunkSize) {
    chunks.push(file.slice(i, i + chunkSize));
  }
  return chunks;
}

/**
 * 获取文件的md5
 * @param file 文件
 * @param chunkSize 分块大小 
 * @param type 类型
 * @returns 返回文件的md5
 */
const getFileMd5: (file: File, chunkSize: number, type?: 'headMd5') => Promise<string> = (file: File, chunkSize: number, type?: 'headMd5') => {
  const chunks = fileChunk(file, chunkSize, type)
  return new Promise((resolve, reject) => {
    let currentChunk = 0; // 从第0块开始读
    const spark = new SparkMD5.ArrayBuffer(); // 实例化SparkMD5用于计算文件hash值
    const fileReader = new FileReader(); // 实例化文件阅读器用于读取blob二进制文件
    fileReader.onerror = () => {
      reject('error')
    };
    fileReader.onload = (e) => {
      spark.append(e.target.result); // 将二进制文件追加到spark中
      currentChunk = currentChunk + 1; // 这个读完就加1，读取下一个blob
      // 若未读取到最后一块，就继续读取；否则读取完成，Promise带出结果
      if (currentChunk < chunks.length) {
        fileReader.readAsArrayBuffer(chunks[currentChunk]);
      } else {
        resolve(spark.end()); // resolve出去告知结果
      }
    };
    // 文件读取器的readAsArrayBuffer方法开始读取文件，从blob数组中的第0项开始
    fileReader.readAsArrayBuffer(chunks[currentChunk]);
  })
}

/**
 * 转换速率（解决设置限速后，偶发出现速率超过限速的大小）
 * @param speed 速率
 * @param uploadSpeed 限速大小
 * @returns 返回处理后的速率
 */
const convertSpeed = (speed: string, uploadSpeed: number) => {
  if (!speed) {
    return;
  }
  const unit = (speed.replace(/[0-9./s]/g, '')).toUpperCase() as 'B' | 'KB' | 'M';
  const size = parseFloat(speed);
  let _unit = 'b/s';
  if (sizeEnum[unit] * size > uploadSpeed) {
    let _number = Math.random() * uploadSpeed;
    if (_number / 1024 > 1) {
      _number = _number / 1024;
      _unit = 'kb/s';
    }
    if (_number / 1024 > 1) {
      _number = _number / 1024;
      _unit = 'M/s';
    }
    return _number.toFixed(1) + _unit;
  }
  return speed;
}

/**
 * 获取图片的base64
 * @param 图片
 */
const getImgToBase64: (file: File) => Promise<string | null> = (file: File) => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.readAsDataURL(file)
    fileReader.onload = (e) => {
      const base64 = (e.target?.result || null) as string | null;
      return resolve(base64)
    }
  })
}

export {
  getComponentProps,
  isFileGone,
  findFileIndex,
  formatSizeAndUnits,
  conversionStrategy,
  fileValidate,
  childFolderValidate,
  updateFileValidate,
  getFilesStatus,
  getFileFailedNum,
  isUploadComplete,
  isCancelable,
  isDeletable,
  splitFileName,
  getPath,
  removeVisibleFile,
  getFileMd5,
  convertSpeed,
  getImgToBase64
};
